﻿using LiteVectorIndex.Engine;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LiteVectorIndex
{
    /// <summary>
    /// 高性能序列化器
    /// </summary>
    public class FastSerializer
    {
        /// <summary>
        /// 序列化向量集合数据，采用GZip压缩后转换为BASE64字符串
        /// </summary>
        /// <param name="data">集合数据</param>
        /// <returns>BASE64数据</returns>
        public static string ToZipBase64(PlainCollectionData data)
        {
            if (data == null)
            {
                return string.Empty;
            }

            // 处理原始数据
            using var ms = new MemoryStream();
            using var bw = new BinaryWriter(ms);

            // 写头信息
            bw.Write(data.Version);
            bw.Write(data.Dimension);
            bw.Write((int)data.MetricTypeInUse);

            // 写向量个数
            bw.Write(data.Ids.Count);

            // 写 ID
            foreach (var id in data.Ids)
                bw.Write(id);

            // 写 Vectors
            foreach (var vec in data.Vectors)
            {
                foreach (var f in vec)
                    bw.Write(f);
            }

            bw.Flush();

            var bytes = ms.ToArray();

            // 压缩数据
            using var ms2 = new MemoryStream();
            using (var gzip = new GZipStream(ms2, CompressionLevel.Fastest))
                gzip.Write(bytes, 0, bytes.Length);

            return Convert.ToBase64String(ms2.ToArray());
        }

        /// <summary>
        /// 反序列化向量集合数据
        /// </summary>
        /// <param name="text">GZip压缩后的BASE64数据</param>
        /// <returns>集合数据</returns>
        public static PlainCollectionData ToCollectionData(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return new PlainCollectionData();
            }

            var compressed = Convert.FromBase64String(text);
            using var ms1 = new MemoryStream(compressed);
            using var gzip = new GZipStream(ms1, CompressionMode.Decompress);
            using var outStream = new MemoryStream();
            gzip.CopyTo(outStream);

            var bytes = outStream.ToArray();

            using var ms = new MemoryStream(bytes);
            using var br = new BinaryReader(ms);

            int version = br.ReadInt32();
            int dimension = br.ReadInt32();
            MetricType metricType = (MetricType)br.ReadInt32();


            var data = new PlainCollectionData
            {
                Version = version,
                MetricTypeInUse = metricType
            };

            int count = br.ReadInt32();

            data.Ids = new List<int>(count);
            data.Vectors = new List<float[]>(count);

            for (int i = 0; i < count; i++)
                data.Ids.Add(br.ReadInt32());

            // 读取向量数据：每个向量有 dimension 个 float
            for (int i = 0; i < count; i++)
            {
                var vec = new float[dimension];
                for (int j = 0; j < dimension; j++)
                    vec[j] = br.ReadSingle();
                data.Vectors.Add(vec);
            }

            return data;
        }
    }
}
